import java.util.*;

class Field {
    public final static int FIELD_TYPE_INVALID = 0;
    public final static int FIELD_TYPE_INT = 1;
    public final static int FIELD_TYPE_STRING = 2;
    public final static int FIELD_TYPE_STRUCT = 3;

    private int type = FIELD_TYPE_INVALID;
    private String strType = "";
    private String name = "";
    private String desc = "";
    private boolean key = false;
    private String value = "";
    private int column = -1;     // excel column index

    public Field() {
    }

    public Field clone() {
        Field field = new Field();
        field.type = this.type;
        field.strType = this.strType;
        field.name = this.name;
        field.desc = this.desc;
        field.key = this.key;
        field.value = this.value;
        field.column = this.column;
        return field;
    }

    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }

    public String getStrType() {
        return this.strType;
    }

    public void setStrType(String strType) {
        this.strType = strType;
    }

    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return this.desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }

    public boolean isKey() {
        return this.key;
    }
    public void setKey(boolean key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }

    public int getColumn() {
        return this.column;
    }

    public void setColumn(int column) {
        this.column = column;
    }

    public String toString() {
        String str = "field:" + this.name + ", type:" + this.type + "," + this.strType + ", desc:" + this.desc + ", key:" + (this.key == true ? "true" : "false");
        if (this.value != "") {
            str += ", value:";
            str += this.value;
        }
        return str;
    }
}

class Struct {
    private String name = "";
    private String desc = "";
    private Field keyField = null;
    private List<Field> fieldList = null;
    private String fileName = "";
    private String sheetName = "";

    public Struct() {
    }

    public Struct clone() {
        Struct struct = new Struct();
        struct.name = this.name;
        struct.desc = this.desc;
        //struct.keyField = this.keyField;
        //struct.fieldList = this.fieldList;
        struct.fileName = this.fileName;
        struct.sheetName = this.sheetName;
        Iterator<Field> it = this.fieldList.iterator();
        while (it.hasNext()) {
            Field field = it.next();
            Field newField = field.clone();
            struct.addField(newField);
            if (newField.isKey()) {
                struct.keyField = newField;
            }
        }

        return struct;
    }

    public Struct(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return this.desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public Field getKeyField() {
        return this.keyField;
    }

    public void setKeyField(Field field) {
        this.keyField = field;
    }

    public void addField(Field field) {
        if (this.fieldList == null) {
            this.fieldList = new ArrayList<>();
        }
        this.fieldList.add(field);
    }

    public List<Field> getFieldList() {
        return this.fieldList;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getSheetName() {
        return sheetName;
    }

    public void setSheetName(String sheetName) {
        this.sheetName = sheetName;
    }

    public String toString() {
        String msg = "\tstruct " + this.name + ", desc:" + this.desc + "fileName:" + this.fileName + ", sheetName:" + this.sheetName + "\n";
        Iterator<Field> it = this.fieldList.iterator();
        while (it.hasNext()) {
            Field field = it.next();
            msg += "\t\t";
            msg += field.toString();
            msg += "\n";
        }
        return msg;
    }
}

class StructMgr {
    private StructMgr() {
    }

    private static StructMgr instance = null;
    private Map<String, Struct> structMap = new HashMap<>();

    public static StructMgr getInstance() {
        if (instance == null) {
            instance = new StructMgr();
        }
        return instance;
    }

    boolean addStruct(Struct struct) {
        if (this.structMap.containsKey(struct.getName())) {
            return false;
        }

        this.structMap.put(struct.getName(), struct);
        return true;
    }

    Struct getStruct(String name) {
        return this.structMap.get(name);
    }

    public Map<String, Struct> getStructMap() {
        return this.structMap;
    }

    public String toString() {
        String msg = "all struct list:\n";
        for (Map.Entry<String, Struct> entry : structMap.entrySet()) {
            Struct struct = entry.getValue();
            msg += struct.toString();
            msg += '\n';
        }
        return msg;
    }
}
